package cc.rengu.redp.flowable.bizrule.rule;

import cc.rengu.redp.flowable.bizrule.commander.AbstractSpClassCommander;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 业务规则校验处理主控
 *
 * @author xushitang
 */
@Slf4j
public class BusiRuleCommander extends AbstractSpClassCommander<BusiRule> {
    private static BusiRuleCommander busiRuleCommander;

    /**
     * 单例模式
     */
    private BusiRuleCommander() {
    }

    private static synchronized void getInstance() {
        if (busiRuleCommander == null) {
            busiRuleCommander = new BusiRuleCommander();
        }
    }

    /**
     * 执行规则处理
     *
     * @param listSpClass 规则类名称列表 ARule001;BRule002;BRule003;...
     * @param validateJson   待校验的数据，不能为null或size=0
     * @param rulePrefixList 可变参数，不需要过滤时可填空
     * @return
     */
    public static RuleResult executeRuleList(
            List<String> listSpClass,
            JSONObject validateJson,
            BusiRulePrefix... rulePrefixList) {
        return BusiRuleCommander.executeRuleList(listSpClass, validateJson, null, rulePrefixList);
    }

    /**
     * 执行规则处理
     *
     * @param listSpClass 规则类名称列表 ARule001;BRule002;BRule003;...
     * @param validateJson   待校验的数据
     * @param requestJson    如待校验数据为null或size=0时，通过getValidateData(requestJson)获取validateJson
     * @param rulePrefixList 可变参数，不需要过滤时可填空
     * @return
     */
    public static RuleResult executeRuleList(
            List<String> listSpClass,
            JSONObject validateJson,
            JSONObject requestJson,
            BusiRulePrefix... rulePrefixList) {

        if (busiRuleCommander == null) {
            getInstance();
        }

        if (listSpClass != null && listSpClass.size() > 0) {
            Integer rulesCount = 0;
            Integer rulesSuitable = 0;
            Integer rulesPassed = 0;
            StringBuilder allExeRulesString = new StringBuilder();

            RuleResult validateResult = null;

            //支持多个规则类

            for (String spClass : listSpClass) {
                BusiRule busiRule = busiRuleCommander.getSpClass(spClass);
                if (busiRule == null) {
                    continue;
                }

                //过滤规则类型
                if (rulePrefixList.length != 0) {
                    int i = 0;
                    for (; i < rulePrefixList.length; i++) {
                        if (rulePrefixList[i].getRulePrefix().equals(busiRule.getRulePrefix())) {
                            break;
                        }
                    }

                    if (i >= rulePrefixList.length) {
                        continue;
                    }
                }

                rulesCount++; //执行总数
                if (rulesCount > 1) {
                    allExeRulesString.append(" ,");
                }
                allExeRulesString.append(spClass);

                //如果需要，获取待处理内容
                JSONObject exeValidateJson = validateJson;
                if (exeValidateJson == null || exeValidateJson.size() <= 0) {
                    if (requestJson == null || requestJson.size() <= 0) {
                        return RuleResult.buildFailureResult("待处理内容为空");
                    } else {
                        exeValidateJson = busiRule.getValidateData(requestJson);
                    }
                }

                busiRule.dataPreHandle(exeValidateJson);

                //业务场景校验
                RuleResult checkResult = busiRule.checkSuitable(exeValidateJson);
                if (checkResult == null) {
                    checkResult = RuleResult.buildFailureResult("场景校验结果为NULL");
                }
                if (RuleResult.FAILURE.equals(checkResult.getCode())) {
                    log.info("规则[{}], 不符合业务场景，原因[{}]", spClass, checkResult.getMessage());
                    continue;
                }

                rulesSuitable++;
                validateResult = busiRule.validateData(exeValidateJson);
                if (validateResult == null) {
                    validateResult = RuleResult.buildFailureResult("规则返回结果为NULL");
                }
                //只要其中一个规则不通过，按全部不通过处理
                if (RuleResult.FAILURE.equals(validateResult.getCode())) {
                    log.info("规则[{}]，校验不通过，原因[{}]", spClass, validateResult.getMessage());
                    break;
                } else {
                    rulesPassed++;
                    log.info("规则[{}]，校验通过。", spClass);
                }
            }

            log.info("本次执行规则有[{}]共[{}]个，其中有[{}]个规则符合当前业务场景，共[{}]个规则校验通过。",
                    allExeRulesString,
                    rulesCount,
                    rulesSuitable,
                    rulesPassed);

            //没有与当前细分场景相适应的规则
            if (rulesSuitable == 0) {
                return RuleResult.buildSuccessResult();
            }

            return validateResult;
        }

        return RuleResult.buildSuccessResult();
    }

    /**
     * 添加规则到内存
     * @param ruleName
     * @param busiRule
     */
    public static void add(String ruleName, BusiRule busiRule) {
        if (busiRuleCommander == null) {
            getInstance();
        }

        busiRuleCommander.initAdd(ruleName, busiRule);
    }

    /**
     * 获取指定类型的规则列表及规则用途描述
     * @param busiRulePrefix
     * @return
     */
    public static Map<String, String> showRulesForConfig(BusiRulePrefix busiRulePrefix) {
        return busiRuleCommander.getCache().entrySet().stream()
                .filter(i -> i.getKey().startsWith(busiRulePrefix.getRulePrefix()))
                .collect(Collectors.toMap(
               k -> k.getKey(),
               v -> v.getValue().getClassDesc()
        ));
    }
}
